package saolei;

import java.util.*;

public class MineField {
    private int mineNum;
    private int xNum;
    private int yNum;
    private ArrayList<Coordinate> coordinates = new ArrayList<Coordinate>();

    public MineField(int mineNum, int xNum, int yNum) {
        this.mineNum = mineNum;
        this.xNum = xNum;
        this.yNum = yNum;
    }

    public void init() {
        // 生成雷区
        MyLogger.logger.info("初始化雷区");
        ArrayList<Integer> mines = new ArrayList<Integer>();
        // 遍历每个坐标是否为雷效率很低，所以用一个数组储存谁为类，值计算类似于二位数组下标
        Random rand = new Random();
        for (int i = 1; i <= this.mineNum;) {
            // 生成雷的坐标
            int x = rand.nextInt(this.xNum) + 1;
            int y = rand.nextInt(this.yNum) + 1;
            int mine = (x - 1) * this.yNum + y;
            if (mineOk(mine, mines) == 1) {
                mines.add(mine);
                i++;
            }
        }
        // 根据雷的坐标得到完整的雷区，等效于一个二维数组
        for (int i0 = 1; i0 <= this.xNum; i0++) {
            for (int i1 = 1; i1 <= this.yNum; i1++) {
                int e = (i0 - 1) * this.yNum + i1;
                if (mines.indexOf(e) == -1) {
                    coordinates.add(new Coordinate(i0, i1, Adts(e, mines).size()));
                } else
                    coordinates.add(new Coordinate(i0, i1, -1));
            }
        }
        return;
    }

    public int isVctory() {
        // 判断是否胜利，0为失败
        int csize = this.coordinates.size();
        for (int i = 0; i < csize; i++) {
            Coordinate current = this.coordinates.get(i);
            if ((current.getIsMine() == 1 && current.getNum() != -1)
                    || (current.getIsMine() != 1 && current.getNum() == -1))
                return 0;
        }
        return 1;
    }

    public ArrayList<Integer> checkGrid(int a) {
        // 点击到空白的方格，显示一大片的区域，返回值为显示区域的下标，包括其本身
        Coordinate e = this.getCoordinates().get(a), current = e;
        ArrayList<Integer> answer = new ArrayList<Integer>();
        int x = e.getX(), y = e.getY(), index = (x - 1) * this.yNum + y - 1;
        answer.add(index);
        for (int i = 0; i < answer.size(); i++) {
            ArrayList<Integer> adts = new ArrayList<Integer>();
            index = answer.get(i);
            x = index / this.yNum + 1;
            y = index % this.yNum + 1;
            if (y < this.yNum)
                adts.add(index + 1);
            if (1 < y)
                adts.add(index - 1);
            if (x < this.xNum)
                adts.add(index + this.yNum);
            if (1 < x)
                adts.add(index - this.yNum);
            for (int i0 = 0; i0 < adts.size(); i0++) {
                current = this.coordinates.get((adts.get(i0)));
                if (answer.indexOf(adts.get(i0)) == -1) {
                    if (current.getNum() > 0) {
                        answer.add(0, adts.get(i0));
                        i++;
                    }
                    if (current.getNum() == 0)
                        answer.add(adts.get(i0));
                }
            }
        }
        return answer;
    }

    public ArrayList<Coordinate> getCoordinates() {
        return coordinates;
    }

    public void printmines() {
        // 测试用，输出雷区
        MyLogger.logger.info("输出雷区");
        for (int i0 = 1; i0 <= this.xNum; i0++) {
            for (int i1 = 1; i1 <= this.yNum; i1++) {
                System.out.print(this.coordinates.get((i0 - 1) * this.yNum + i1 - 1).getNum() + "\t");
            }
            System.out.println("");
        }
    }

    private int mineOk(int mine, ArrayList<Integer> mines) {
        // 是否可以成为一颗雷，返回1为可以
        if (mines.indexOf(mine) != -1 || isClose(mine, mines) == 1)
            return 0;
        return 1;
    }

    private int isClose(int e, ArrayList<Integer> mines) {
        // 判断是否会构成封闭图形，1为会构成封闭图形
        ArrayList<Integer> stack = new ArrayList<Integer>();
        int x = (e - 1) / this.yNum + 1, y = (e - 1) % this.yNum + 1;
        stack.add(e);
        while (stack.size() > 0) {
            int current = stack.remove(stack.size() - 1);
            ArrayList<Integer> adts = Adts(current, mines);
            if (((x == 1 || y == 1 || x == this.xNum || y == this.yNum) && adts.size() >= 1) || adts.size() >= 2) {
                int asize = adts.size();
                for (int i = 0; i <= asize - 1; i++) {
                    int adt = adts.get(i);
                    if (stack.indexOf(adt) != -1)
                        stack.add(adt);
                }
            } else
                return 0;
        }
        return 1;
    }

    private ArrayList<Integer> Adts(int e, ArrayList<Integer> mines) {
        // 得到相邻的为炸弹点，包括对角线的坐标
        ArrayList<Integer> answer = new ArrayList<Integer>();
        ArrayList<Integer> adts = new ArrayList<Integer>();
        int x = (e - 1) / this.yNum + 1, y = (e - 1) % this.yNum + 1;
        if (y < this.yNum)
            adts.add(e + 1);
        if (1 < y)
            adts.add(e - 1);
        if (x < this.xNum)
            adts.add(e + this.yNum);
        if (1 < x)
            adts.add(e - this.yNum);
        if (y < this.yNum && x < this.xNum)
            adts.add(e + 1 + this.yNum);
        if (y < this.yNum && 1 < x)
            adts.add(e + 1 - this.yNum);
        if (x < this.xNum && 1 < y)
            adts.add(e - 1 + this.yNum);
        if (1 < y && 1 < x)
            adts.add(e - 1 - this.yNum);
        int bsize = mines.size();
        for (int i0 = 0; i0 <= bsize - 1; i0++) {
            int current = mines.get(i0);
            for (int i1 = 0; i1 <= adts.size() - 1; i1++) {
                if (current == adts.get(i1)) {
                    answer.add(adts.remove(i1));
                    break;
                }
            }
        }
        return answer;
    }
}

class Coordinate {
    private int x;// 横坐标
    private int y;// 纵坐标
    private int num;// 周围炸弹数，为-1时表示炸弹
    private int isMine;// 用户是否觉得这是一个炸弹，0为非，1为是，-1为存疑，初始值为非

    public Coordinate(int x, int y, int num) {
        this.x = x;
        this.y = y;
        this.num = num;
        this.isMine = 0;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getNum() {
        return num;
    }

    public int getIsMine() {
        return isMine;
    }

    public void setIsMine(int isMine) {
        this.isMine = isMine;
    }
}